#include "login_authority_task.h"

#include <bonddict/IBondDict.h>
#include <bondlib/BondContainer.h>
#include <core/Utility.h>
#include <core/sharedata/login_data.h>
#include <qbkernel/include/qb_base.h>
#include <qbprotocol/include/SSQBModel.h>
#include <qbtools/message/MessagePoster.h>
#include <uam/UserAccountManager.h>

#include <thread>

#include "../MessageProcess.h"

extern IDictUpdate* auth_dict_updater;
namespace qb {
typedef void (CLoginAuthorityTask::*authorityFunc)(void);
struct AuthorityTask {
  _eFunID_t funid;
  authorityFunc func;
};

AuthorityTask authorityTasks[] = {
    {E_FID_QB_USER_PERMISSION_REQ, &CLoginAuthorityTask::RequestUserPermission},
    {E_FID_QB_CDC_AUTHORITY_REQ_V2, &CLoginAuthorityTask::RequestCDCAuthority},
    {E_FID_QB_CSI_AUTHORITY_REQ, &CLoginAuthorityTask::RequestCSIAuthority},
};

CLoginAuthorityTask::CLoginAuthorityTask() {
  for (uint32_t i = 0; i < sizeof(authorityTasks) / sizeof(AuthorityTask);
       i++) {
    qbBase::getMessageBond()->RegisterMsgProcessor(authorityTasks[i].funid,
                                                   this);
  }
  m_ptr.reset(this);
}

CLoginAuthorityTask::~CLoginAuthorityTask() {}

void CLoginAuthorityTask::StartImpl() {
  SSUserAccountManager::instance().SetCDCAutority(NULL);
  SSUserAccountManager::instance().init();
  CBondContainer::instance().ClearCDCDataAll();
  loginData::instance().SetCurrentStatus(eNetStatus_Authority);

  m_setAuthority.clear();
  for (uint32_t i = 0; i < sizeof(authorityTasks) / sizeof(AuthorityTask);
       i++) {
    m_setAuthority.insert(authorityTasks[i].funid);
    (this->*authorityTasks[i].func)();
  }
  SSUserAccountManager::instance().requestSystime();
  SSUserAccountManager::instance().requestBroker();
  SSUserAccountManager::instance().requestQbFlags();
  SSUserAccountManager::instance().requestGlobalSwitch();
  SSUserAccountManager::instance().requestUserInfo();
  SSUserAccountManager::instance().requestMobileConfirm();
  SSUserAccountManager::instance().requestQBConditionGroupQueryNew();

  std::shared_ptr<CLoginAuthorityTask> tmpPtr = m_ptr;
  std::thread t([tmpPtr]() {
    if (auth_dict_updater && !auth_dict_updater->checkLoadStatus())
      auth_dict_updater->WaitFirstLoad(29, 65);
    if (tmpPtr.use_count() == 1)  // TODO: use better method
      return;
    tmpPtr->setDictReady();
  });
  t.detach();
}

void CLoginAuthorityTask::TerminateImpl() {}

void CLoginAuthorityTask::RequestUserPermission() {
  SSRequestMsg Req;
  memset(&Req, 0, sizeof(SSRequestMsg));
  Req.m_MsgType = SSReqType_Message;
  Req.m_FuncID = E_FID_QB_USER_PERMISSION_REQ;

  QBAuthorityQueryReq_t req;
  QBAuthorityQueryReq_t* ptr = &req;
  memset(ptr, 0, sizeof(QBAuthorityQueryReq_t));
  strcpy(ptr->m_UserId, loginData::instance().UserInfo().strUserID.c_str());
  strcpy(ptr->m_CompanyId,
         loginData::instance().UserInfo().strCompanyId.c_str());
  Req.m_pRequest = (void*)ptr;

  MessagePoster poster(&Req, [](qb::proto::Message& msg, qb::SSRequestMsg*) {
    qb::proto::VariantMap submsg;
    submsg.setString("UserId", loginData::instance().UserInfo().strUserID);
    submsg.setString("CompanyId",
                     loginData::instance().UserInfo().strCompanyId);
    msg.SetMap("xQBAuthorityQueryReq", submsg);
  });
  if (poster.send() < 0) {
    NotifyFailed(eNetStatus_Authority, eNetError_SendToServerFailed);
  }
}

void CLoginAuthorityTask::RequestCDCAuthority() {
  SSRequestMsg Req;
  memset(&Req, 0, sizeof(SSRequestMsg));
  Req.m_MsgType = SSReqType_Message;
  Req.m_FuncID = E_FID_QB_CDC_AUTHORITY_REQ;

  xCDCAuthorityReq_c req;
  FIELDCOPY(req.m_UserId, loginData::instance().UserInfo().strUserID.c_str());
  FIELDCOPY(req.m_CompanyId,
            loginData::instance().UserInfo().strCompanyId.c_str());
  Req.m_pRequest = (void*)&req;

  MessagePoster poster(&Req, nullptr);
  if (poster.send() < 0) {
    NotifyFailed(eNetStatus_Authority, eNetError_SendToServerFailed);
  }

  Req.m_RequestID = 0;
  Req.m_FuncID = E_FID_QB_CDC_AUTHORITY_REQ_V2;
  MessagePoster poster2(&Req, nullptr);
  if (poster2.send() < 0) {
    NotifyFailed(eNetStatus_Authority, eNetError_SendToServerFailed);
  }
}

void CLoginAuthorityTask::RequestCSIAuthority() {
  SSRequestMsg Req;
  memset(&Req, 0, sizeof(SSRequestMsg));
  Req.m_MsgType = SSReqType_Message;
  Req.m_FuncID = E_FID_QB_CSI_AUTHORITY_REQ;

  xCSIAuthorityReq_c req;
  Req.m_pRequest = (void*)&req;

  MessagePoster poster(&Req, [](qb::proto::Message& msg, qb::SSRequestMsg*) {
    qb::proto::VariantMap submsg;
    submsg.setString("UserId", loginData::instance().UserInfo().strUserID);
    submsg.setString("CompanyId",
                     loginData::instance().UserInfo().strCompanyId);
    msg.SetMap("xCSIAuthorityReq", submsg);
  });
  if (poster.send() < 0) {
    NotifyFailed(eNetStatus_Authority, eNetError_SendToServerFailed);
  }
}

void CLoginAuthorityTask::setDictReady() {
  m_dictReady = true;
  if (0 == m_setAuthority.size()) {
    NotifyLoginStep(eNetStatus_Authority, 0);
    taskFinish();
  }
}

void CLoginAuthorityTask::OnTimeout() {
  // 用户权限是必须的，其他可以暂时收不到
  auto iter = m_setAuthority.find(E_FID_QB_USER_PERMISSION_REQ);
  if (iter != m_setAuthority.end()) return CTask::OnTimeout();

  NotifyLoginStep(eNetStatus_Authority, 0);
  taskFinish();
}

void CLoginAuthorityTask::AuthorityTaskFinish(_eFunID_t funcid) {
  std::set<_eFunID_t>::iterator it = m_setAuthority.find(funcid);
  if (it != m_setAuthority.end()) {
    m_setAuthority.erase(it);
  }

  if (0 == m_setAuthority.size() && m_dictReady) {
    NotifyLoginStep(eNetStatus_Authority, 0);
    taskFinish();
  }
}

void CLoginAuthorityTask::taskFinish() {
  /*	for (uint32_t i = 0; i < sizeof(authorityTasks) / sizeof(AuthorityTask);
     i++)
          {
                  qbBase::getMessageBond()->UnRegisterMsgProcessor(authorityTasks[i].funid,
     this);
          }*/

  NotifyFinished();
}

STDMETHODIMP_(void)
CLoginAuthorityTask::OnResponse(THIS_ int32_t funcId, const SSAckMsg& msg) {
  if (!msg.m_pRet) {
    if (funcId == E_FID_QB_USER_PERMISSION_REQ)
      NotifyFailed(eNetStatus_Authority, eNetError_DataParseError);
    return;
  }

  if (E_FID_QB_USER_PERMISSION_REQ == funcId) {
    xQBUserPermissionAck_c* pdata = (xQBUserPermissionAck_c*)msg.m_pRet;
    SSUserAccountManager& uam = SSUserAccountManager::instance();
    if (strcmp(uam.GetUserInfo().m_UserId, pdata->m_UserId) != 0 ||
        strcmp(uam.GetUserInfo().m_CompanyId, pdata->m_CompanyId) != 0) {
      NotifyFailed(eNetStatus_Authority, eNetError_DataParseError);
      return;
    }

    if (msg.m_IsReceving == 0) AuthorityTaskFinish((_eFunID_t)funcId);
  } else if (E_FID_QB_CDC_AUTHORITY_REQ_V2 == funcId) {
    AuthorityTaskFinish((_eFunID_t)funcId);
  } else if (E_FID_QB_CSI_AUTHORITY_REQ == funcId) {
    AuthorityTaskFinish((_eFunID_t)funcId);
  }
}
}  // namespace qb
